<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title></title>
	<style type="text/css">
		*{
			margin: 0;
			padding: 0;
		}
		html,body{
			width: 100%;
			height: 100%;
			color: #fff;
		}
		body{
			background-image: linear-gradient(#000,#1d2d3f);
		}
		#myBg{
			position: fixed;
			left: 0;
			top: 0;
			width: 100%;
			height: 100%;
			transition: 1s;
			background-image: linear-gradient(#1d253f 20%,#e36060 140%);
		}
		.bg1{
			opacity: 1;
		}
		.bg2{
			opacity: 0;
		}
		#container{
			position: fixed;
			left: 0;
			top: 0;
			width: 100%;
			height: 100%;
			perspective: 800px;
			z-index: 2;
		}
		#container .center{
			position: absolute;
			left: 50%;
			top: 50%;
			transform-style: preserve-3d;
			/* animation: rotate 25s linear infinite; */
		}
		@keyframes rotate{
			from{transform: rotateX(-20deg) rotateY(0);}
			to{transform: rotateX(-20deg) rotateY(1turn);}
		}
		.card{
			position: absolute;
			left: 0;
			top: 0;
			width: 60px;
			height: 60px;
			background-color: #c7ddff88;
			transform-origin: center;
			transition: 2s;
			overflow: hidden;
		}
		.card:hover{
			background-color: #c7ddff;
		}
		.card .inner{
			width: 100%;
			height: 100%;
			box-sizing: border-box;
			border: 2px solid #c0e6ff;
			font-size: 12px;
			text-align: center;
			line-height: 24px;
			transition: .4s;
			-webkit-user-select: none;
			-moz-user-select: none;
			-ms-user-select: none;
			user-select: none;
			cursor: pointer;
		}
		.card img{
			display: block;
			width: 100%;
			height: 100%;
			transition: .3s;
		}
		.card:hover .inner{
			border-color: #fff;
			background-color: #c7ddff;
		}
		.card:hover img{
			filter: brightness(120%);
			border-color: #fff;
			background-color: #c7ddff;
		}
		#myCanvas{
			position: fixed;
			left: 0;
			top: 0;
			z-index: 1;
		}
	</style>
</head>
<body>
<div id="myBg" class="bg1"></div>
<canvas id="myCanvas"></canvas>
<div id="container">
	<!-- <button type="button" onclick="fun1()">test1</button>
	<button type="button" onclick="fun2()">test2</button> -->
	<div class="center">
	</div>
</div>
<script type="text/javascript">
	!function (e,w){
		function Particle(option) {
			this.originOption = {
				el: "#myCanvas",// canvas 选择器 ( 可配置 )
				f: 1200, // 焦距 ( 可配置 )
				dis: 14000, // 视距 ( 可配置 )
				rY: 0, // 初始 y 轴旋转角度 ( 可配置 )
				rX: 0, // 初始 x 轴旋转角度 ( 可配置 )
				mode: 1, // 模式 ( 可配置 )
				preEmit: false, // 是否预运行 ( 可配置 )
				draggable: true, // 是否允许拖拽 ( 可配置 )
				pList: [], // 集中管理粒子 ( 可配置 )
				mainWidth: w.innerWidth, // 画布宽
				mainHeight: w.innerHeight, // 画布高
				canvas: null, // canvas dom
				cx: null, // canvas2d 上下文对象
				timer: null, // 动画计时器
				ms: 0, // 当前时间
				isPress: false, // 鼠标是否按下
				dragX: 0, // x 方向拖拽量
				dragY: 0, // y 方向拖拽量
				_currX: 0, // x 方向临时拖拽量
				_currY: 0 ,// y 方向临时拖拽量
				userDis: false, // 用户是否设置视距
				userN: false, // 用户是否设置横纵数量
				zoomQuotiety: 30, // 滚轮缩放速度
				glow: false,
				showTail: false, // 是否开启拖尾模式
			}
			Object.assign(this, this.originOption, option)
			;option.dis && (this.userDis = true)
			;(option.nX || option.nY) && (this.userN = true)
			this.init()
		}
		Particle.prototype.expend = function(obj) {Object.assign(this, obj)}
		Particle.prototype.expend({
			init() {
				this.dragY = this.rX * 180 / Math.PI
				this.dragX = this.rY * 180 / Math.PI
				this.canvas = e.querySelector(this.el)
				if(!this.canvas){
					throw Error("Please provide an enable canvas element selector for option 'el'")
					return false
				}
				if(this.canvas.isUsed){
					throw Error("Reduplicate canvas element, please provide another enable canvas element selector for option 'el', or use function 'destroy()' to remove this instance first!")
					return false
				}
				this.cx = this.canvas.getContext("2d")
				this.canvas.setAttribute("width",this.mainWidth)
				this.canvas.setAttribute("height",this.mainHeight)
				this.showTail && (this.canvas.style.mixBlendMode = "screen")
				this.canvas.isUsed = true // 占用
				this.emitterPos = [this.mainWidth / 2, this.mainHeight / 2]
				this.addEvent()
				this.emit()
			},
			addEvent() {
				this.windowMousedown = () => {
					if(this.draggable){
						this.isPress = true
						this._currX = event.pageX + this.dragX
						this._currY = event.pageY / 2 + this.dragY
					}
				}
				this.windowMousemove = () => {
					if (this.isPress && this.draggable) {
						this.dragX = this._currX - event.pageX
						this.dragY = this._currY - event.pageY / 2
						this.rY = this.dragX * Math.PI / 180
						this.rX = this.dragY * Math.PI / 180
					}
				}
				this.windowMouseup = () => {
					if(this.draggable){
						this.isPress = false
					}
				}
				this.windowMousewheel = event => {
					if(this.draggable){
						if(event.deltaY){
							this.dis += event.deltaY * this.zoomQuotiety
						}else{ // 兼容火狐
							this.dis += event.detail * 33 * this.zoomQuotiety
						}
					}
				}
				this.windowResize = () => {
					this.mainWidth = w.innerWidth
					this.mainHeight = w.innerHeight
					this.canvas.setAttribute("width",this.mainWidth)
					this.canvas.setAttribute("height",this.mainHeight)
				}
				w.addEventListener("mousedown",this.windowMousedown)
				w.addEventListener("mousemove",this.windowMousemove)
				w.addEventListener("mouseup",this.windowMouseup)
				w.addEventListener("mousewheel",this.windowMousewheel)
				w.addEventListener("DOMMouseScroll",this.windowMousewheel)
				w.addEventListener("resize",this.windowResize)
			},
			destroy(){
				// 解绑所有事件
				w.removeEventListener("mousedown",this.windowMousedown)
				w.removeEventListener("mousemove",this.windowMousemove)
				w.removeEventListener("mouseup",this.windowMouseup)
				w.removeEventListener("mousewheel",this.windowMousewheel)
				w.removeEventListener("DOMMouseScroll",this.windowMousewheel)
				w.removeEventListener("resize",this.windowResize)
				// 清除计时器
				clearInterval(this.timer)
				clearInterval(this.cTimer)
				this.cx.clearRect(0,0,this.mainWidth,this.mainHeight)
				// 解除 canvas dom 占用
				this.canvas.isUsed = false
			},
			emit() {
				this["mode"+this.mode]()
			},
			mode1(){
				this.dis = this.userDis ? this.dis : 14000
				this.f = 800
				this.draggable = false
				this.rX = 1.2
				this.dragY = this.rX * 180 / Math.PI
				// ;(e.body || e.documentElement).style.backgroundImage = "linear-gradient(to top,#ffeabe 0,#5d2f2f 100%)"
				// 创建粒子
				var count = 0
				var nX = this.userN ? this.nX : 40
				var nY = this.userN ? this.nY : 20
				var pWidth = 1600 // 六边形边长
				var dis = 0 // 六边形间距
				var g3 = Math.pow(3,0.5) // 提前计算根号 3 的值
				var sixElement = [ // 六边形基元各个顶点坐标
					[0, 0],
					[pWidth, 0],
					[pWidth * 1.5, pWidth / 2 * g3],
					[pWidth, pWidth * g3],
					[0, pWidth * g3],
					[-pWidth / 2, pWidth / 2 * g3]
				]
				var oOffsetX = (pWidth * 3 + dis * g3) // 双六边形基元 X 偏移
				var oOffsetY = (pWidth * g3 + dis) // 双六边形基元 Y 偏移
				function off(sixEl,oX,oY){
					var arr = []
					sixEl.forEach(axis=>{
						arr.push([axis[0] + oX, axis[1] + oY])
					})
					return arr
				}
				var sixElement2 = off(sixElement,oOffsetX/2,oOffsetY/2) // 初次右下偏移的新六边形
				sixElement = [[...sixElement],[...sixElement2]] // 获得双六边形基元坐标集 (坐标x12)
				var realNX = Math.round(nX / 2)
				for(var i = 0; i < nY; i++){
					for(var j = 0; j < realNX; j++){
						var posArr = []
						sixElement.forEach(sixEl=>{
							var arr = []
							sixEl.forEach(p=>{
								var x = p[0] + (j-realNX/2) * oOffsetX
								var y = p[1] + (i-nY/2) * oOffsetY
								// arr.push([x, y, Math.pow(x*y,2) / 200000]) // 迪拉修姆光流
								arr.push([x, y-8000, -5000])
							})
							posArr.push(arr)
						})
						posArr.forEach(pos=>{ // 创建两次, 原位 和 右下偏移位
							// *********************  创建单个六边形对象
							this.pList.push({
									pos,
									color: [Math.floor(200-Math.random()*80),Math.floor(255-Math.random()*40),255],
									opacity: 1,
									count: ++count
									// count: Math.floor(Math.random() * 1000)
							})
						})
					}
				}
				this.cx.globalAlpha = .5
				// 绘制
				this.draw(()=>{
					this.pList.forEach(p => {
						// 透明度动画
						p.opacity = Math.abs(Math.sin(this.ms / 2000 + p.count)) *.8  - .2
						p.opacity = p.opacity < .2 ? .2 : p.opacity
						// this.cx.fillStyle = "rgba("+p.color+","+p.opacity+")"
						this.cx.fillStyle = "rgba(180,180,200,"+p.opacity+")"
						this.cx.beginPath()
						var visable = true
						var mul;
						p.pos.forEach((sixEl,index)=>{
							// 开始绘制立体六边形
							var z = sixEl[2] + Math.sin(this.ms/150+p.count) * 100
							
							var p2d = this.deDiv([sixEl[0],sixEl[1],z])
							if(p2d.mul < 0){
								visable = false
								return false
							}
							if(index === 0){
								this.cx.moveTo(...p2d.res)
							}else{
								this.cx.lineTo(...p2d.res)
							}
							mul = p2d.mul
						})
						this.cx.closePath()
						// visable && this.cx.fill()
						var temp = Math.abs(Math.sin(this.ms / 1000 + p.count + Math.PI))
						this.cx.strokeStyle = "rgba("+p.color+","+ temp +")"
						// this.cx.strokeStyle = "rgb("+p.color+")"
						// this.cx.strokeStyle = "rgba(180,180,200,"+p.opacity+")"
						mul = mul > 1 ? 1 : mul
						this.cx.lineWidth = 32*mul
						this.cx.stroke()
					})
				})
			},
			draw(frame,isStatic,isFromConner){
				var t = this.showTail ? 10 : 16
				if(isStatic){
					frame.call(this)
				}else{
					this.timer = setInterval(() => {
						this.ms = performance.now()
						this.cx.save()
						!this.showTail && this.cx.clearRect(0,0,this.mainWidth,this.mainHeight)
						this.showTail && (this.cx.fillStyle = "#00000011",this.cx.fillRect(0,0,this.mainWidth,this.mainHeight))
						if(!isFromConner){
							this.cx.translate(this.mainWidth / 2, this.mainHeight / 2)
						}
						frame()
						this.cx.restore()
					}, 16)
				}
			},
			deDiv(p3d) {
				var res = this.rotateX(...this.rotateY(...p3d, this.rY), this.rX)
				// var res = this.rotateY(...this.rotateX(...p3d, this.rX), this.rY)
				var mul = this.f / (this.dis - res[2] - this.f) // 计算透视缩放系数
				// var mul = .4-this.dis / 80000 // 平行透视
				return {
					res: [res[0] * mul, res[1] * mul],
					mul,
					origin: res
				}
			},
			rotateY(x, y, z, a) {
				// 绕 Y 轴旋转角度 a
				var x1 = x,
					z1 = z;
				x1 = x * Math.cos(a) - z * Math.sin(a)
				z1 = z * Math.cos(a) + x * Math.sin(a)
				return [x1, y, z1]
			},
			rotateX(x, y, z, a) {
				// 绕 X 轴旋转角度 a
				var y1 = y,
					z1 = z;
				y1 = y * Math.cos(a) - z * Math.sin(a)
				z1 = z * Math.cos(a) + y * Math.sin(a)
				return [x, y1, z1]
			},
		})
		w.Particle = Particle
	}(document,window)
	var pDemo = new Particle({})
</script>
<script type="text/javascript">
	var oCon = document.querySelector("#container .center")
	var cardList = []
	var styleList1 = []
	var styleList2 = []
	var R = 300
	for(let i = 0; i < 10; i++){
		for(let j = 0; j < 10; j++){
			let c = document.createElement("div")
			oCon.appendChild(c)
			c.className = "card"
			// c.innerHTML = `<div class="inner">二次元<br>永远滴神</div>`
			c.innerHTML = `<div class="inner"><img src="./avatars/${ Math.floor(Math.random()*17)+1 }.png"/></div>`
			c.style.transition = `all ${Math.random() + 1.5}s ${Math.random()/2}s,background-color .4s`
			cardList.push({
				el: c,
				index: [i,j],
				transition: Math.random()*.2 + .3,
			})
			styleList1.push({
				pos: [(i-5)*70,(j-5)*70]
			})
		}
	}
	for(let i = 0; i < cardList.length; i++){
		let a = i * 360 / 20
		styleList2.push(`translate3d(${ Math.cos(a/ 180 * Math.PI) * R }px,${ i * 4 - 300 }px,${ Math.sin(a/ 180 * Math.PI) * R }px) rotateY(${ (90-a)%360 }deg)`)
	}
	
	function fun1(){
		for(let i = 0; i < cardList.length; i++){
			// cardList[i].el.style = ""
			cardList[i].el.style.transform = ""
			cardList[i].el.style.left = styleList1[i].pos[0] + "px"
			cardList[i].el.style.top = styleList1[i].pos[1] + "px"
			// cardList[i].el.style.transition = `transform ${Math.random() + 1.5}s,background-color .4s`
		}
	}
	function fun2(){
		for(let i = 0; i < cardList.length; i++){
			// cardList[i].el.style = ""
			cardList[i].el.style.left = 0
			cardList[i].el.style.top = 0
			cardList[i].el.style.transform = styleList2[i]
			// cardList[i].el.style.transition = `transform ${Math.random()*.5 + 1}s,background-color .4s`
		}
	}
	var curr = 1
	var timeout = null
	window.addEventListener("click",()=>{
		if(!event.target.classList.contains("inner")){
			window["fun"+curr]()
			curr = curr == 1 ? 2 : 1
			myBg.className = myBg.className == 'bg1' ? 'bg2' : 'bg1'
		}
	})
	setTimeout(()=>{
		fun2()
	},100)
	var oCount = 0
	var timer = setInterval(() => {
		oCon.style.transform = `rotateX(-20deg) rotateY(${ oCount/8 }deg)`
		oCount++
	},16)
	oCon.onmouseover = () => {
		if(curr == 2){
			timeout && clearTimeout(timeout)
			clearInterval(timer)
			oCon.style.transition = ".4s"
			oCon.style.transform = `rotateX(-20deg) rotateY(${ 0 }deg)`
		}
		
	}
	oCon.onmouseout = () => {
		if(curr == 2){
			timeout = setTimeout(() => {
				// oCount = 0
				oCon.style.transform = `rotateX(-20deg) rotateY(${ (oCount/8+180)%360-180 }deg)`
				setTimeout(() => {
					oCon.style.transition = ""
					timer = setInterval(() => {
						oCon.style.transform = `rotateX(-20deg) rotateY(${ (oCount/8+180)%360-180 }deg)`
						oCount++
					},16)
				},400)
			},600)
		}
	}
	var windowMousewheel = event => {
		if(event.deltaY){
			oCount += event.deltaY / 5
		}else{ // 兼容火狐
			oCount += event.detail * 33 / 5
		}
	}
	window.addEventListener("mousewheel",windowMousewheel)
	window.addEventListener("DOMMouseScroll",windowMousewheel)
	
</script>
</body>
</html>
